package base

import (
	"context"
	"fmt"
	"time"
)

/*
异步协程
非阻塞
func asyncFunction1(name string, delay time.Duration) {
	time.Sleep(delay)
	fmt.Println("hello,%s after %s\n", name, delay)
}

func asyncFunction2(name string, delay time.Duration) {
	time.Sleep(delay)
	fmt.Println("hello,%s after %s \n", name, delay)
}

func asyncFunction3(name string, delay time.Duration) {
	time.Sleep(delay)
	fmt.Println("hello,%s after %s \n", name, delay)
}

func AsyncMain() {
	fmt.Println("start")
	go asyncFunction1("Kimi", 2*time.Second)
	go asyncFunction2("CaiKun", 3*time.Second)
	go asyncFunction3("虾仁", 4*time.Second)
	// 主函数继续执行其他任务，不会被阻塞
	fmt.Println("Main function is still running...")
	time.Sleep(4 * time.Second)
	fmt.Println("end")
}
*/
/*
通道（Channels):阻塞异步
func channelsFunction1(delay time.Duration, resultChan chan int) {
	time.Sleep(delay)
	result := 213941
	resultChan <- result
}

func channelsFunction2(delay time.Duration, resultChan chan int) {
	time.Sleep(delay)
	result := 594188
	resultChan <- result
}

func AsyncMain() {
	fmt.Println("主线程开始执行.......")
	resultChan1 := make(chan int)
	resultChan2 := make(chan int)
	go channelsFunction1(2*time.Second, resultChan1)
	go channelsFunction2(3*time.Second, resultChan2)
	for i := 1; i < 3; i++ {
		select {
		case result := <-resultChan1:
			fmt.Println("Received result:", result)
		case result := <-resultChan2:
			fmt.Println("Received result:", result)
		case <-time.After(5 * time.Second):
			fmt.Println("Operation timed out")
		}
	}
}
*/
/*
在所有 goroutine 启动后，调用 WaitGroup 的 Wait 方法来阻塞主 goroutine，直到计数器归零，即所有 goroutine 都已完成。
func asyncFounction1(name string, delay time.Duration, wg *sync.WaitGroup) {
	defer wg.Done() // 减少WaitGroup的计数
	time.Sleep(delay)
	fmt.Printf("Hello, %s after %s\n", name, delay)
}

func asyncFounction2(name string, delay time.Duration, wg *sync.WaitGroup) {
	defer wg.Done() // 减少WaitGroup的计数
	time.Sleep(delay)
	fmt.Printf("Hello, %s after %s\n", name, delay)
}

func AsyncMain() {
	var wg sync.WaitGroup
	// 假设我们有两个任务需要执行
	fmt.Println("Mainthrad start ......")
	wg.Add(1)
	go asyncFounction1("胡八一", 2*time.Second, &wg)
	wg.Add(1)
	go asyncFounction2("王胖子", 3*time.Second, &wg)
	wg.Wait()
	fmt.Println("Mainthrad end ......")
}
*/
/*
context包可以用来在Goroutines之间传递取消信号、超时控制和截止时间等。
*/
//func asyncFunction(ctx context.Context, delay time.Duration) {
//	select {
//	case <-time.After(delay):
//		fmt.Println("异步操作完成")
//	case <-ctx.Done():
//		fmt.Println("异步操作取消!")
//	}
//}
//
//func AsyncMain() {
//	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
//	defer cancel()
//	go asyncFunction(ctx, 2*time.Second)
//	<-ctx.Done()
//	//检查超时原因
//	if ctx.Err() != nil {
//		fmt.Println("Error:", ctx.Err())
//	}
//}
//当设置时间和阻塞运行时间相同时候,使用chanel不会被触发超时
func asyncFunction2(ctx context.Context, delay time.Duration) {
	time.Sleep(delay)
	fmt.Println("Operation completed!")
}

func asyncFunction(done chan struct{}, ctx context.Context) {
	asyncFunction2(ctx, 3*time.Second)
	done <- struct{}{}
}

/*
在Go语言中，表达式 done := make(chan struct{}, 1) 创建了一个通道（channel），其中使用了 struct{} 类型和数字 1 作为参数。这两个参数的意义如下：
struct{}:
这是一个空的结构体类型，它不包含任何字段。
在这里，struct{} 用作通道中传递的“信号”的类型。由于我们只是想发送一个信号，而不是传递实际的数据，所以使用空结构体是一个轻量级的选择。
使用 struct{} 而不是定义一个新的类型或者使用其他类型，可以保持代码的简洁性，并且 struct{} 已经足够用来表示一个简单的完成信号。
1:这个数字指定了通道的缓冲大小。在这个例子中，1 意味着通道可以存储一个 struct{} 类型的值。
缓冲区允许通道在没有接收者准备好读取的情况下，暂时保存一个值。这样，发送操作不会因为找不到接收者而阻塞。
在这个上下文中，缓冲区的存在意味着你可以在不立即等待接收方的情况下，发送一个信号。这对于控制异步操作非常有用，因为它允许发送方在接收方准备好接收之前，提前发送信号。
综上所述，done := make(chan struct{}, 1) 创建了一个可以存储一个空结构体值的缓冲通道。这个通道通常用于通知某个异步操作的完成，而不需要传递任何实际的数据。使用缓冲通道可以避免在发送信号时发生阻塞，这对于并发编程中的协调操作非常有用。
*/
func AsyncMain() {
	ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
	defer cancel()
	done := make(chan struct{}, 1)
	go asyncFunction(done, ctx)
	select {
	case <-done:
		fmt.Println("Operation finished successfully!")
	case <-ctx.Done():
		fmt.Println("Operation cancelled due to timeout!")
	}
	if ctx.Err() != nil {
		fmt.Println("Erro:", ctx.Err())
	}
}
